; *****************************************************************
; Input/Output 32 bits functions (protected mode)
; Reindeer OS - boot loader
;
; Copyrights 2011 Michal Saman, m.saman@designplus.cz.
; This source code is release under the Apache License 2.0.
; http://www.apache.org/licenses/LICENSE-2.0
; *****************************************************************
bits 32

%define	VIDMEM		0xB8000
%define	COLS		80
%define	LINES		25
%define	CHAR_ATTR	14			; (white text on black background)

_CurX	db 0		; actual position of cursor
_CurY	db 0

;*****************************************
; Putch32()
; BL - char to print
;*****************************************
Putch32:

	pusha
	mov		edi, VIDMEM
	; determine current cursor position
	xor		eax, eax
	mov		ecx, COLS*2					; in mode 7 (text mode) has every charecter on screen 2 bytes (ascii code, attribute)
	mov		al, byte [_CurY]
	mul		ecx							; do y*COLS*2 result save to eax
	push	eax							; save eax

	mov		al, byte [_CurX]
	mov		cl, 2
	mul		cl
	pop		ecx							; restore y*COLS*2
	add		eax, ecx					; add X offset, eax now contains memory address of actual cursor position

	add		edi, eax					; edi = VIDMEM + eax (actual cursor position)

	; check if input char is new line
	cmp		bl, 0x0A
	je		.row

	; print a character (in BL)
	mov		dl, bl
	mov		dh, CHAR_ATTR
	mov		word [edi], dx

	; update cursor position
	inc		byte [_CurX]
	cmp		byte [_CurX], COLS				; check if we are at end of line
	je		.row
	jmp		.done

.row:
	mov		byte [_CurX], 0
	inc		byte [_CurY]

.done:
	popa
	ret

;*************************************************
; Puts32()
;	ebx - address of string that we want to print
;*************************************************

Puts32:
	pusha
	push	ebx
	pop		edi

.loop:
	mov		bl, byte [edi]
	cmp		bl, 0					; is char null - end of string
	je		.done

	call Putch32					; print char in BL

.next:
	inc edi
	jmp	.loop

.done:
	mov	bh, byte [_CurY]	; get current position
	mov	bl, byte [_CurX]
	call	MoveCur			; update cursor

	popa					; restore registers, and go back
	ret

;****************************************************
; MoveCur()
;    - bh - Y position
;    - bl - X position
;****************************************************

MoveCur:
	pusha
	xor		eax, eax
	mov		ecx, COLS
    mov		al, bh			; get Y position
	mul		ecx				; multiply y*COLS
	add		al, bl			; add X offset
	mov		ebx, eax

	; set low byte to VGA register
	mov		al, 0x0F		; cursor location low byte
	mov		dx, 0x03D4		; port of CRT index register
	out		dx, al

	mov		al, bl			; current position of cursor is in EBX, bl is low byte, bh is high byte
	mov		dx, 0x03D5		; write it to data register
	out		dx, al

	xor		eax, eax		; clear eax

	; set high byte to VGA register
	mov		al, 0x0E		; cursor location high byte
	mov		dx, 0x03D4		; port of CRT index register
	out		dx, al

	mov		al, bh
	mov		dx, 0x03D5
	out		dx, al			; write the high byte

	popa
	ret

;******************************************************
; GetCurPos()
;   - sets current position of curstor to _CurY, _CurX
;******************************************************

GetCurPos:
	pusha
	xor		eax, eax

	mov		al, 0x0F		; cursor location low byte
	mov		dx, 0x03D4		; port of CRT index register
	out		dx, al

	mov		dx, 0x03D5		; read it from data register
	in		al, dx
	mov		bl, al			; store it in BL

	xor		eax, eax

	mov		al, 0x0E		; cursor location high byte
	mov		dx, 0x03D4		; port of CRT index register
	out		dx, al

	mov		dx, 0x03D5		; read it from data register
	in		al, dx
	mov		bh, al			; store it in BH

	xor		eax, eax

	mov		ax, bx
	mov		cl,	COLS
	div		cl				; celociselne deleni AX = AX \ COLS
							; y = al, x = ah
	mov		[_CurY], al		; vysledek celociselneho deleli = Y;
	mov		[_CurX], ah		; zbytek celociselneho deleni = X;
	popa
	ret

;******************************************************
; ClrScr32()
;******************************************************

ClrScr32:
	pusha
	mov		edi, VIDMEM
	mov		cx, 2000
	mov		al, ' '
	mov		ah, CHAR_ATTR
	rep		stosw
	mov		byte [_CurY], 0
	mov		byte [_CurX], 0
	popa
	ret
